package com.ruoyi.kubernetes.service.impl;

import com.ruoyi.kubernetes.models.RoleBindingRequestData;
import com.ruoyi.kubernetes.service.IKubernetesClientRoleBindingService;
import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
import io.fabric8.kubernetes.api.model.rbac.Subject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.util.Collections;
import java.util.List;

@Slf4j
@Service
public class KubernetesRoleBindingService implements IKubernetesClientRoleBindingService {

    @Autowired
    private KubernetesClientService kubernetesClientService;

    private static String GROUP_KIND_NAME="Group";

    private static String USER_KIND_NAME="User";

    private static String API_GROUP="rbac.authorization.k8s.io";

    @Override
    public boolean addBinding(RoleBindingRequestData userRoleBindingData) {
        boolean result;
        if (userRoleBindingData.isClusterBinding()){
            result = addClusterRoleBinding(userRoleBindingData);
        }else {
            result = addRoleBinding(userRoleBindingData);
        }
        return result;
    }

    private boolean addRoleBinding(RoleBindingRequestData userRoleBindingData){
        RoleBinding roleBinding = getRoleBindingTemplate();
        roleBinding.getRoleRef().setName(userRoleBindingData.getRoleName());
        roleBinding.getMetadata().setName(userRoleBindingData.getName());
        roleBinding.getMetadata().setNamespace(userRoleBindingData.getNamespace());
        Subject subject = getSubject(userRoleBindingData);
        roleBinding.setSubjects(Collections.singletonList(subject));
        if (kubernetesClientService.getKubernetesClient().rbac().roleBindings().inNamespace(userRoleBindingData.getNamespace()).withName(userRoleBindingData.getName()).get()!=null){
            return true;
        }
        try {
            kubernetesClientService.getKubernetesClient().rbac().roleBindings().inNamespace(userRoleBindingData.getNamespace()).create(roleBinding);
            return true;
        }catch (Exception exception){
            log.error(exception.getMessage());
            return false;
        }
    }

    private boolean addClusterRoleBinding(RoleBindingRequestData userRoleBindingData){
        ClusterRoleBinding clusterRoleBinding = getClusterRoleBindingTemplate();
        clusterRoleBinding.getRoleRef().setName(userRoleBindingData.getRoleName());
        clusterRoleBinding.getMetadata().setName(userRoleBindingData.getName());
        Subject subject = getSubject(userRoleBindingData);
        clusterRoleBinding.setSubjects(Collections.singletonList(subject));
        if(kubernetesClientService.getKubernetesClient().rbac().clusterRoleBindings().withName(userRoleBindingData.getName()).get()!=null){
            return true;
        }
        try {
            kubernetesClientService.getKubernetesClient().rbac().clusterRoleBindings().create(clusterRoleBinding);
            return true;
        }catch (Exception exception){
            log.error(exception.getMessage());
            return false;
        }
    }

    private Subject getSubject(RoleBindingRequestData userRoleBindingData){
        Subject subject = new Subject();
        if (userRoleBindingData.isGroupBinding()) {
            subject.setKind(GROUP_KIND_NAME);
            subject.setName(userRoleBindingData.getGroupName());
        }else {
            subject.setKind(USER_KIND_NAME);
            subject.setName(userRoleBindingData.getUsername());
        }
        subject.setApiGroup(API_GROUP);
        return subject;
    }

    @Override
    public boolean deleteBinding(RoleBindingRequestData userRoleBindingData) {
        boolean result;
        if (userRoleBindingData.isClusterBinding()){
            result = kubernetesClientService
                    .getKubernetesClient()
                    .rbac()
                    .clusterRoleBindings()
                    .withName(userRoleBindingData.getName())
                    .delete();
        }else {
            result = kubernetesClientService
                    .getKubernetesClient()
                    .rbac()
                    .roleBindings().inNamespace(userRoleBindingData.getNamespace())
                    .withName(userRoleBindingData.getName())
                    .delete();
        }
        return result;
    }

    @Override
    public boolean deleteBindings(List<RoleBindingRequestData> userRoleBindingDataList) {
        userRoleBindingDataList.forEach(this::deleteBinding);
        return true;
    }

    private ClusterRoleBinding getClusterRoleBindingTemplate(){
        try {
            File file = ResourceUtils.getFile("classpath:kubernetes-templates/clusterrole-binding-template.yml");
            return kubernetesClientService.getKubernetesClient().rbac().clusterRoleBindings().load(file).get();
        }catch (Exception exception){
            log.error(exception.getMessage());
            return null;
        }
    }

    private RoleBinding getRoleBindingTemplate() {
        try {
            File file = ResourceUtils.getFile("classpath:kubernetes-templates/role-binding-template.yml");
            return kubernetesClientService.getKubernetesClient().rbac().roleBindings().load(file).get();
        }catch (Exception exception){
            log.error(exception.getMessage());
            return null;
        }
    }
}
